package br.ufc.apsoo.repositories;

import java.io.Serializable;

import javax.persistence.EntityManager;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

import br.com.caelum.vraptor.ioc.Component;
import br.ufc.apsoo.exceptions.HospedeJaCadastradoException;
import br.ufc.apsoo.models.Hospede;
import br.ufc.apsoo.models.Pais;

@Component
public class HospedeRepositoryImpl extends Repository<Hospede, Serializable>
		implements TodosHospedes {

	private final Session session;

	protected HospedeRepositoryImpl(EntityManager entityManager) {
		super(entityManager);
		session = (Session) entityManager.getDelegate();
	}

	@Override
	public void atualiza(Hospede hospede) throws HospedeJaCadastradoException {
		Hospede hospedeComEmail = porEmail(hospede.getEmail());
		if (hospedeComEmail != null
				&& !hospedeComEmail.getId().equals(hospede.getId())) {
			throw new HospedeJaCadastradoException(
					"Ja existe um hospede cadastrado com este email!");
		}
		Hospede hospedeComCpf = porCpf(hospede.getCpf());
		if (hospedeComCpf != null
				&& !hospedeComCpf.getId().equals(hospede.getId())) {
			throw new HospedeJaCadastradoException(
					"Ja existe um hospede cadastrado com este CPF!");
		}
		Hospede hospedeDoPaisComPassaporte = selecionarEstrangeiro(
				hospede.getPais(), hospede.getPassaporte());
		if (hospedeDoPaisComPassaporte != null
				&& !hospedeDoPaisComPassaporte.getId().equals(hospede.getId())) {
			throw new HospedeJaCadastradoException(
					"Ja existe um hospede deste pais cadastrado com este passaporte.");
		}

		if (!hospede.getPais().ehOBrasil()) {
			hospede.setCpf(null);
		} else {
			hospede.setPassaporte(null);
		}
		
		this.update(hospede);
	}

	@Override
	public void cadastra(Hospede hospede) throws HospedeJaCadastradoException {
		if (porEmail(hospede.getEmail()) != null) {
			throw new HospedeJaCadastradoException(
					"Ja existe um hospede cadastrado com este email!");
		}
		if (porCpf(hospede.getCpf()) != null) {
			throw new HospedeJaCadastradoException(
					"Ja existe um hospede cadastrado com este CPF!");
		}
		if (selecionarEstrangeiro(hospede.getPais(), hospede.getPassaporte()) != null) {
			throw new HospedeJaCadastradoException(
					"Ja existe um hospede deste pais cadastrado com este passaporte.");
		}
		
		if (!hospede.getPais().ehOBrasil()) {
			hospede.setCpf(null);
		} else {
			hospede.setPassaporte(null);
		}

		this.create(hospede);
	}

	@Override
	public Hospede porCpf(String cpf) {
		Criteria criteria = session.createCriteria(Hospede.class);
		criteria.add(Restrictions.like("cpf", cpf, MatchMode.EXACT));
		return (Hospede) criteria.uniqueResult();
	}

	@Override
	public Hospede porEmail(String email) {
		Criteria criteria = session.createCriteria(Hospede.class);
		criteria.add(Restrictions.like("email", email, MatchMode.EXACT)
				.ignoreCase());
		return (Hospede) criteria.uniqueResult();
	}

	@Override
	public Hospede porId(Long id) {
		return find(id);
	}

	@Override
	public Hospede selecionarEstrangeiro(Pais pais, String passaporte) {

		if (pais.ehOBrasil()) {
			return null;
		}
		Criteria criteria = session.createCriteria(Hospede.class);
		criteria.add(Restrictions.eq("pais.id", pais.getId()));
		criteria.add(Restrictions.eq("passaporte", passaporte));
		return (Hospede) criteria.uniqueResult();
	}

}
